<?php

class   OptionParser
{

    private $__options = array();
    private $__args = array();

    private $__helps = array();

    public  function    __construct()
    {
    }

    public  function    addOption($short, $long, $dest, $help='', $type='string', $default=NULL )
    {
        // short args maybe empty 
        //if ( empty($short) ) {
        //    throw new Exception(__CLASS__ . ": invalid short-name");
        //}
        if ( empty($long) ) {
            throw new Exception(__CLASS__ . ": invalid long-name");
        }
        if ( empty($dest) ) {
            throw new Exception(__CLASS__ . ": invalid dest-name");
        }

        if ( ('-h' == $short) || ('--help' == $long) ) {
            throw new Exception( __CLASS__ . ": -h|--help option is preserved." );
        }

        $opt = array( 'short' => $short, 'long' => $long, 'dest' => $dest, 'help' => $help, 'type' => $type );

        $this->__helps[] = $opt;
    }

    public  function    parse($args, $index_start = 1)
    {
        $key = false;

        $count = count($args);
        for ($i=$index_start; $i<$count; $i++) {
            if ( '-' == $args[$i][0] ) {

                if ( ('-h' == $args[$i]) || ('--help' == $args[$i]) ) {
                    $this->usage();
                    exit ( 0 );
                }

                if ( !empty($key) ) {
                    throw new Exception(sprintf("%s : incomplete option '%s'", __CLASS__, $args[$i - 1]));
                }

                $hit = false;
                foreach ( $this->__helps as $opt ) {
                    $arg_current = $args[$i];
                    $value_current = false;
                    list($arg_current, $value_current) = split('=', $arg_current, 2);
                    
                    if ( (0 == strcmp($arg_current, $opt['short'])) || (0 == strcmp($arg_current, $opt['long'])) ) {
                        if ( ('bool' == $opt['type']) || ('boolean' == $opt['type']) ) {
                            $this->__options[ $opt['dest'] ] = true;
                        }
                        else {
                            $key = $opt['dest'];
                            
                            if ($value_current) {
                                $this->__options[ $key ] = $value_current;
                                $key = false;
                            }
                        }

                        $hit = true;
                        break;
                    }
                }
                if ( !$hit ) {
                    throw new Exception(sprintf("%s : invalid option '%s'", __CLASS__, $args[$i]));
                }
            }
            else {
                if ( empty($key) ) {
                    $this->__args[] = $args[$i];
                }
                else {
                    $this->__options[ $key ] = $args[$i];
                    $key = false;
                }
            }
        } 

        if ( !empty($key) ) {
            throw new Exception(sprintf("%s : incomplete option '%s'", __CLASS__, $args[$i - 1]));
        }

        return  array($this->__options, $this->__args);
    }

    public  function    usage()
    {
        if ( !isset($this->__helps['-h']) ) {
            $short = '-h';
            $long = '--help';
            $dest = 'help';
            $help = 'show this help message and exit';
            $opt = array( 'short' => $short, 'long' => $long, 'dest' => $dest, 'help' => $help, 'type'=>'bool' );

            $this->__helps[] = $opt;
        }
        
        ob_start();
        echo "\nUsage : \n\n";
        foreach ( $this->__helps as $opt ) {
            if ( ('bool' == $opt['type']) || ('boolean' == $opt['type']) )  {
                echo "\t",$opt['short'],"|",$opt['long'],"\t",$opt['help'],"\n";
            }
            else {
                echo "\t",$opt['short'],"|",$opt['long']," ",strtoupper($opt['dest']),"\t",$opt['help'],"\n";
            }
        }
        $help = ob_get_contents();
        ob_end_clean(); 
        echo $help,"\n";
    }

}

